Kapitel 4 Das Klassendesign (Teil 1)
4.1 Einführung in die Objektorientierung  
Die beiden wichtigsten Begriffe, die im Mittelpunkt der objektorientierten Betrachtungen stehen, sind die der Klasse und des Objekts. Was ist darunter zu verstehen?
Stellen Sie sich ein Architekturbüro vor, das ein Einfamilienwohnhaus plant und den Bauplan als Ergebnis aller anfänglichen Forderungen und der daraus resultierenden Berechnungen zeichnet. Der Bauplan enthält die Abmessungen des Grundrisses der einzelnen Etagen, die Angaben, wo welche Fenster und Türen eingebaut werden, die Mauerdicken, die Lage der Elektroverkabelung, Heizungsverrohrung usw. Der fertige und freigegebene Bauplan dient anschließend als Vorlage der konkreten Bauausführung, also zur Realisierung dessen, was der Bauplan beschreibt.
Vielleicht hat der Architekt sogar die Möglichkeit, denselben Bauplan noch einmal zu benutzen, um darauf basierend ein zweites oder gar ein drittes Haus zu erstellen. Die Häuser müssen jedoch nicht identisch sein, sie können sich in Einzelheiten unterscheiden: Die Außenfassade des ersten Hauses mag geputzt sein, die des zweiten geklinkert, ein Haus wird mit einer Ölheizung betrieben, das andere nutzt die Fernwärme.
Der Bauplan eines Hauses ist nichts weiter als eine Vorlage, im weitesten Sinne die Beschreibung einer Schablone, die zur Realisierung konkreter Häuser dient. Projiziert auf die objekt- orientierte Welt ist der Bauplan als eine Klasse zu verstehen, ein fertig gebautes Haus als ein Objekt. Liegt ein Bauplan (= Klasse) vor, kann er dazu dienen, x-beliebig viele Häuser (= Objekte) zu erstellen, die sich durchaus unterscheiden dürfen.
|
Eine Klasse beschreibt einen Datentyp und ist eine Schablone, die angibt, wie Objekte dieser Klasse aussehen sollen. Ein Objekt hingegen ist die konkrete Realisierung einer Klassenbeschreibung, ein tatsächlich existierendes »Ding«.
|
In der objektorientierten Programmierung spricht man von einem Objekt oder auch von einem konkreten Objekt, wenn aus der Klassendefinition heraus etwas »Gegenständliches« erzeugt wird. Ein weiterer, häufig benutzter Begriff ist der der Klasseninstanz oder einfach nur Instanz. Sie können diese Begriffe synonym nebeneinander verwenden, sie besagen dasselbe.
Ein Objekt wird durch bestimmte, charakteristische Merkmale beschrieben, die in der Klassendefinition festgelegt werden müssen. Diese werden als Eigenschaften bezeichnet. Beispielsweise kann ein Objekt vom Typ Person durch den Namen, die Augenfarbe, die Schuhgröße und das Geschlecht im Rahmen der anwendungsspezifischen Forderungen ausreichend beschrieben werden.
Im einfachsten Fall wird eine Eigenschaft als Variable innerhalb der Klassenstruktur definiert und als Feld bezeichnet, wie beispielsweise Farbe im folgenden Codefragment der Klasse Auto:
| Class Auto
|
| Public Farbe As Integer
|
| End Class
|
Ein Objekt wäre demnach beispielsweise myCar:
| Dim myCar As Auto = New Auto
|
Wie mit Visual Basic üblich, wird bei einer Deklaration zuerst der Variablenname angegeben, dahinter folgt der Datentyp. Vergessen Sie nicht: Eine Klassendefinition ist die Beschreibung eines Datentyps. Mit dem Schlüsselwort New wird das Objekt schließlich konkretisiert.
Eine andere, etwas kürzere Schreibweise ist ebenfalls zulässig:
Eine Klasse abstrahiert Objekte aber nicht nur in der Weise, dass Objekte gleichen Typs nur durch die in der Klasse definierten Eigenschaften beschrieben werden. Objekte können auch Operationen ausführen, beispielsweise um die Eigenschaften zu manipulieren. Stellen Sie sich vor, Sie würden die Klasse Auto implementieren. Ein Objekt vom Typ Auto besitzt Eigenschaften wie AnzahlDerRäder, Hubraum oder Farbe, aber ein Auto-Objekt kann noch viel mehr: Es kann mit einer bestimmten Geschwindigkeit von A nach B fahren, beim Auftreten einer sich anbahnenden, verkehrsgefährdenden Situation kann es hupen. Fahren und Hupen können nicht durch Eigenschaften beschrieben werden. Es sind vielmehr Operationen, die das Verhalten eines Autos beschreiben. Im objektorientierten Sprachgebrauch wird eine von einem Objekt ausgeführte Operation auch als Methode bezeichnet.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 4.1 Die fiktive Klasse »Auto
Methoden werden in einer Klassenstruktur als Prozedur definiert, ähnlich wie Main, die uns in Kapitel 3 als Einstiegspunkt in eine Konsolenanwendung diente. Das folgende Codefragment demonstriert die Klasse Auto mit den drei Feldern Farbe, AnzahlDerRäder und Hubraum sowie der Methode Fahren:
| Class Auto
|
| Public Farbe As Integer
|
| Public AnzahlDerRaeder As Integer
|
| Public Hubraum As Double
|
| Public Sub Fahren()
|
| ' Anweisungen
|
| End Sub
|
| End Class
|
Da wir nun eine Klasse vorliegen haben, wollen wir uns auch ansehen, wie wir damit arbeiten können. Dazu wird die Methode Main wie folgt codiert:
| Sub Main()
|
| Dim myCar As New Auto
|
| ' Festlegung des Hubraums
|
| myCar.Hubraum = 1995.45
|
| ' das Auto fahren lassen
|
| myCar.Fahren()
|
| End Sub
|
Zuerst besorgen wir uns ein Objekt vom Typ Auto. Das Objekt heißt im weiteren Verlauf myCar und hat die Eigenschaften Farbe, AnzahlDerRäder und Hubraum. Alle Eigenschaften müssen nicht unbedingt auf einen objektspezifischen Wert festgelegt werden, sondern nur die, die wirklich notwendig sind. Hier ist es nur die Eigenschaft Hubraum, der exemplarisch ein Wert zugewiesen wird. Anschließend wird die Methode Fahren aufgerufen. Beachten Sie den Punktoperator, der dazu dient, eine Eigenschaft oder Methode auf ein bestimmtes Objekt aufzurufen. Handelt es sich um eine Eigenschaft, muss ihr mit dem Zuweisungsoperator noch der gewünschte Wert zugewiesen werden.
Spielen mehrere konkrete Auto-Objekte im Programm eine Rolle, muss die Klasse Auto wiederholt instanziiert werden. Im folgenden Code liegen exemplarisch zwei vor, die mit myCar und yourCar bezeichnet sind und sich in ihrem Hubraum unterscheiden.
| Dim myCar As New Auto
|
| myCar.Hubraum = 2995
|
| Dim yourCar As New Auto
|
| yourCar.Hubraum = 1599
|
4.1.1 Das objektorientierte Paradigma  
Die objektorientierte Programmierung lässt sich generell auf vier elementare Schlüsselkonzepte reduzieren:
|
Klassen |
|
Datenkapselung |
|
Vererbung |
|
Polymorphie |
Nachstehend folgt eine kurze Beschreibung dieser Begriffe, damit Sie schon eine erste grobe Orientierung und Vorstellung davon bekommen. Im weiteren Verlauf des Buches wird auf die theoretischen und programmiertechnischen Details sowie die daraus resultierenden Konsequenzen bei der Implementierung eines durchdachten und schlüssigen Klassendesigns noch genau eingegangen.
Klassen
Eine Klasse realisiert einen Datentyp und ist das fundamentale Sprachelement der objektorientierten Programmierung. Eine Klasse beschreibt, durch welche Eigenschaften sich Objekte dieses Typs voneinander unterscheiden und welche Fähigkeiten diese Objekte haben. Ein Objekt ist in der objektorientierten Begriffswelt nichts anderes als eine Variable vom Typ einer bestimmten Klasse.
Datenkapselung
Die Eigenschaften eines Objekts sind im Grunde genommen nichts anderes als Variablen, die einen Wert enthalten. Denken Sie an das oben angeführte Beispiel eines Auto-Objekts. Sie können die Farbe eines Autos bei einer Neuwagenbestellung festlegen – vorausgesetzt, Sie übergeben einen Wert, der eine Farbe beschreibt, die im aktuellen Angebot enthalten ist. Ein ungültiger Farbwert darf nicht akzeptiert werden.
An dieser Stelle kommt die Datenkapselung ins Spiel. Der Farbwert wird einer Variablen zugewiesen, auf die der Anwender nicht direkt zugreifen kann, denn die Daten sind Private deklariert. Stattdessen wird die Wertzuweisung durch die Umleitung über eine Methode ausgewertet, in der die Zulässigkeit der Zuweisung überprüft wird. Eine Klasse schützt (kapselt) so ihre Daten vor dem direkten Zugriff. Das ist ein ganz wesentlicher Aspekt der Objektorientierung.
Vererbung
Objekte, die von Natur aus verschiedenartig sind, können dennoch über gemeinsame Merkmale verfügen. Stellen Sie sich beispielsweise vor, Sie müssen in Ihrem Projekt die drei Klassen Hubschrauber, Starrflügler und Zeppelin implementieren. Allen drei Typen sind unter anderem die Eigenschaften
|
Baujahr |
|
Kaufpreis |
|
Hersteller |
gemein. Es liegt nahe, eine separate Klasse Luftfahrzeug zu definieren, die nur die gemeinsamen Merkmale enthält. Ein Hubschrauber wäre dann ein spezieller Typ der Klasse Luftfahrzeug, ebenso der Starrflügler und der Zeppelin. Das Resultat dieser Überlegung ist eine Klassenhierarchie, in der die Luftfahrzeug-Klasse die »Mutterklasse« bildet, von der die drei anderen Abkömmlinge sind.
Eine Klasse, die ihre Merkmale untergeordneten Klassen zur Verfügung stellt, wird als Basisklasse bezeichnet, eine untergeordnete Klasse, welche die Merkmale einer Basisklasse übernimmt, als abgeleitete Klasse oder Subklasse. Abgeleitete Klassen übernehmen die Eigenschaften und Methoden der übergeordneten Basisklasse, sie beerben die Basisklasse und ergänzen die geerbten Merkmale durch typspezifische. Ein herkömmliches Flugzeug (Starrflügler) wird beispielsweise eine spezifische Eigenschaft Spannweite aufweisen, was ein Flugzeug von einem Zeppelin und einem Hubschrauber unterscheidet, da diese Eigenschaft für diese beiden Typen keine Bedeutung hat. Andererseits kann ein Hubschrauber wiederum durch den Rotordurchmesser detaillierter beschrieben werden, ein Zeppelin durch das Gasvolumen.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 4.2 Vererbungshierarchie Luftfahrzeuge
 Hier klicken, um das Bild zu Vergrößern
Abbildung 4.3 Die Klasse »Starrflügler« beerbt die Klasse »Luftfahrzeug«.
Die herausragendsten Vorteile der Vererbung, die auch als Implementierungsvererbung bezeichnet wird, sind die folgenden:
|
Die Reduzierung von Programmcode, da gemeinsame Eigenschaften und Methoden nur in der Basisklasse implementiert werden müssen. |
|
Gemeinsame Eigenschaften der Klassen stehen nicht an mehreren Stellen im Programmcode und müssen somit auch nur einmal geprüft und gegebenenfalls geändert werden. Man spricht hierbei auch von der Konsistenz des Programmcodes. |
In der .NET-Klassenbibliothek sind einige tausend Klassen vordefiniert und den unterschiedlichsten Aufgabenbereichen zugeordnet. Alle Klassen, selbst die benutzerdefinierten, lassen sich auf eine gemeinsame Basisklasse zurückführen, nämlich auf die Klasse Object. Nach dem, was Sie bisher zu der Vererbung erfahren haben, bedeutet das, dass alle Methoden dieser allgemeinsten .NET-Klasse an sämtliche anderen .NET-Klassen vererbt werden.
Polymorphie
Die Implementierungsvererbung stellt die Wiederbenutzung von Programmcode einer Basisklasse durch eine abgeleitete Klasse sicher. Verwandte Objekte können aber auch eine Gemeinsamkeit haben, die sich nur in der Codeimplementierung unterscheidet. Die drei Objekte Hubschrauber, Starrflügler und Zeppelin können zwar allesamt fliegen, das Verhalten muss aber in der Methode Fliegen jeder Klasse unterschiedlich beschrieben werden.
Dazu wird in der Basisklasse das gemeinsame Merkmal festlegt, hier Fliegen, das aber implementierungslos bleibt. Die Subklassen beerben die Basisklasse, müssen aber ihrerseits die erforderliche typspezifische Programmlogik bereitstellen. Wird aus einer inhomogenen Menge verschiedener Luftfahrzeug-Objekte (z. B. einem Array vom Typ Luftfahrzeug, das Objekte aller drei Typen enthält) die Methode Fliegen aufgerufen, wird für jedes Objekt im Array die typspezifische Implementierung ausgeführt. Polymorphie (zu Deutsch: Vielgestaltigkeit) bedeutet, dass erst zur Laufzeit einer Anwendung bestimmt wird, welche Fliegen-Implementierung aufgerufen werden muss, da dies beim Kompilieren noch nicht bekannt ist.
Das grundlegende Verständnis der Polymorphie dürfte wohl der schwierigste Teil der Objekt-orientierung sein. Wenn wir uns mit diesem Begriff detailliert auseinander setzen, werden Sie jedoch sehr schnell die Vorzüge zu schätzen lernen.
4.1.2 Vorteile der objektorientierten Programmierung  
Die objektorientierte Programmierung ist nicht einfach zu lernen, darüber gibt es keinen Zweifel. Dennoch hat sich das Konzept in den vergangenen Jahren in nahezu allen Programmiersprachen durchgesetzt. Wenn alle Welt davon spricht und der objektorientierte Ansatz in aller Munde ist, muss es für ihn ein paar schlagkräftige Argumente geben.
Wiederverwendbarkeit: Klassen modularisieren eine Anwendung in unabhängige Einheiten. Sie verwalten zusammengehörende Daten und gruppieren ähnliche Methoden. Klassen können bausteinähnlich in verschiedenen Programmen – in der .NET-Laufzeitumgebung sogar vollkommen unabhängig von der verwendeten Programmiersprache – gleichwertig eingesetzt werden. Als Konsequenz dessen ändert sich auch der Arbeitsablauf der Programmierung: Programme müssen nicht mehr in allen Einzelheiten neu geschrieben werden, sie werden zu einem großen Teil aus fertigen Komponenten zusammengesetzt – vergleichbar mit der Entwicklung und dem Zusammenbau eines Motors, bei dem im Wesentlichen genormte Maschinenteile (Schrauben, Bolzen etc.) zum Einsatz kommen.
Wartungsaufwand: Eine Klasse kapselt ihre Daten sowie die interne Implementierung ihrer Methoden gegenüber der Außenwelt und kann daher problemlos an neue Anforderungen angepasst werden. Anwendungsprogramme, welche die Dienste einer Klasse nutzen, bemerken davon nichts. Eine Klasse kann als eigene, separate und unabhängige Einheit getestet werden. Damit ist es auch vollkommen ausreichend, die Klassenimplementierung nur einmal ausgiebig zu testen. Verläuft der Test positiv, wird die Klasse mit jeder Anwendung zufrieden stellend zusammenarbeiten. Das Testen im Umfeld mehrerer Anwendungsprogramme entfällt und stellt damit die Effizienz der Programmierung sicher.
Fehleranfälligkeit: Die Kapselung bewirkt, dass Objekte den Zugriff auf die Daten selbst kontrollieren und eine fehlerhafte Datenmanipulation und die daraus resultierende Inkonsistenz abwehren können.
4.1.3 Zusammenfassung  
Es ist sehr wichtig, dass Ihnen schon zum jetzigen Zeitpunkt die fundamentalen Begriffe des objektorientierten Konzepts geläufig sind. Sie sollten verstanden haben, was sich hinter einer Klasse verbirgt, was durch ein Objekt beschrieben wird, und insbesondere müssen Sie auch schon prinzipiell verstanden haben, was die Vererbung für die Entwicklung konzeptionell objektorientierter Systeme bedeutet. Sie werden in allen weiteren Abschnitten immer wieder mit den in diesem Abschnitt erläuterten Begriffen konfrontiert, auch wenn das entsprechende Thema vielleicht noch nicht einer genaueren Betrachtung unterzogen worden ist.
Fassen wir daher noch einmal alle wichtigen Aussagen zusammen:
|
Die vier Schlüsselkonzepte des objektorientierten Paradigmas lauten: Klassen, Datenkapselung, Vererbung und Polymorphie. |
|
In der objektorientierten Programmierung dient eine Klassendefinition als Vorlage für Objekte. Eine Klassendefinition beschreibt einen Datentyp und enthält die charakteristischen Merkmale, die den Objekten dieses Typs eigen sind. |
|
Objekte sind die konkrete Realisierung einer Klasse. Sie stellen etwas Existenzielles dar, vergleichbar mit den Objekten des täglichen Lebens. Ein Objekt wird erzeugt, indem eine Klasse instanziiert wird. |
|
Kennzeichnend für Objekte sind deren Eigenschaften und Methoden. Eigenschaften beschreiben den Zustand eines Objekts, Methoden charakterisieren die Verhaltensweisen. |
|
Eigenschaften werden im einfachsten Fall durch Variablen beschrieben, Methoden durch Prozeduren. Die Eigenschaften und Methoden einer Klasse können an eine untergeordnete Klasse vererbt werden. Die abgeleitete, also erbende Klasse verfügt über die geerbten Eigenschaften und kann sie durch weitere typspezifische ergänzen. |
|
Alle Klassen der .NET-Klassenbibliothek sowie alle benutzerdefinierten Klassen erben die Merkmale der obersten Basisklasse Object. |
|